package com.onesports.intelligent.k12.polarlight.service.sys;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.onesports.framework.kit.common.util.BeanUtils;
import com.onesports.framework.kit.common.util.ParamUtils;
import com.onesports.intelligent.k12.polarlight.common.domain.entity.BaseEntity;
import com.onesports.intelligent.k12.polarlight.common.errors.exceptions.BusinessException;
import com.onesports.intelligent.k12.polarlight.constant.BizConstants;
import com.onesports.intelligent.k12.polarlight.constant.SystemCodeConstants;
import com.onesports.intelligent.k12.polarlight.domain.dto.sys.RoleDTO;
import com.onesports.intelligent.k12.polarlight.domain.entity.sys.*;
import com.onesports.intelligent.k12.polarlight.domain.vo.common.AuthTreeVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.sys.DataScopeTableVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.sys.RoleVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.sys.SysDataScopeSelectVO;
import com.onesports.intelligent.k12.polarlight.enums.DataScopeTypeEnum;
import com.onesports.intelligent.k12.polarlight.enums.MenuType;
import com.onesports.intelligent.k12.polarlight.mapper.sys.RoleMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 角色Service
 *
 * @author Wsy
 **/
@Service
@RequiredArgsConstructor
@Slf4j
public class RoleService extends ServiceImpl<RoleMapper, Role> {

    private final RoleMapper roleMapper;
    private final RoleMenuService roleMenuService;
    private final MenuService menuService;
    private final AccountRoleService accountRoleService;
    private final DataScopeService dataScopeService;

    /**
     * 添加角色
     *
     * @param dto 角色dto
     */
    @Transactional(rollbackFor = Exception.class)
    public Role add(RoleDTO dto, String organizationId,String systemCode) {
        //校验角色名称是否重复
        this.checkRoleName(dto, organizationId);

        //添加角色
        Role role = BeanUtils.copyProperties(dto, Role.class);
        role.setOrganizationId(organizationId);
        this.roleMapper.insert(role);
        //添加角色权限
        this.addRoleAuth(dto.getMenuIds(), role.getId());
        //添加角色数据权限
        DataScopeTypeEnum dataScopeTypeEnum = DataScopeTypeEnum.ORGANIZATION;
        if(SystemCodeConstants.ORGANIZATION.equals(systemCode)){
            dataScopeTypeEnum = DataScopeTypeEnum.CAMPUS;
        }
        if(CollectionUtils.isNotEmpty(dto.getDataScopeIds())){
            addDataAuth(dto.getDataScopeIds(), role.getId(),dataScopeTypeEnum);
        }
        return role;
    }

    /**
     * 获取或创建超级管理员角色
     *
     * @param organizationId 机构ID
     * @return
     */
    public Role getSuperRole(String organizationId) {
        List<Role> roles = roleMapper.selectList(new LambdaQueryWrapper<Role>().eq(Role::getIsSuper, true)
                .eq(Role::getOrganizationId, organizationId));
        if (CollectionUtils.isNotEmpty(roles)) {
            return roles.get(0);
        }
        RoleDTO dto = new RoleDTO();
        dto.setRoleName(BizConstants.SUPER_ADMIN_ROLE);
        dto.setIsSuper(true);
        dto.setWholeData(true);
        return add(dto, organizationId,SystemCodeConstants.ORGANIZATION);
    }

    /**
     * 校验角色名称
     *
     * @param dto            入参
     * @param organizationId 机构id
     */
    private void checkRoleName(RoleDTO dto, String organizationId) {
        if(BizConstants.SUPER_ADMIN_ROLE.equals(dto.getRoleName())&&!dto.getIsSuper()){
            throw new BusinessException("禁止操作超级管理员数据");
        }
        LambdaQueryWrapper<Role> roleQuery = new QueryWrapper<Role>().lambda()
                .eq(Role::getRoleName, dto.getRoleName())
                .eq(Role::getOrganizationId, organizationId)
                .ne(ParamUtils.isNotEmpty(dto.getId()), BaseEntity::getId, dto.getId());
        List<Role> roles = this.roleMapper.selectList(roleQuery);
        if (ParamUtils.isNotEmpty(roles)) {
            throw new BusinessException("角色不能重复，请重新输入");
        }

    }


    /**
     * 添加角色权限
     *
     * @param menuIds 权限菜单id
     * @param roleId  角色id
     */
    private void addRoleAuth(List<String> menuIds, String roleId) {
        if (ParamUtils.isNotEmpty(menuIds)) {
            List<RoleMenu> roleMenus = new ArrayList<>();
            for (String menuId : menuIds) {
                RoleMenu roleAuth = RoleMenu.builder().roleId(roleId).menuId(menuId).build();
                roleMenus.add(roleAuth);
            }
            this.roleMenuService.saveBatch(roleMenus);
        }

    }

    /**
     * 添加角色数据权限
     *
     * @param dataScopeIds 数据权限ID
     * @param roleId       角色id
     */
    private void addDataAuth(List<String> dataScopeIds, String roleId, DataScopeTypeEnum dataScopeType) {
        if (ParamUtils.isNotEmpty(dataScopeIds)) {
            List<SysDataScope> dataScopes = new ArrayList<>();
            for (String targetId : dataScopeIds) {
                SysDataScope dataScope = new SysDataScope();
                dataScope.setRoleId(roleId);
                dataScope.setTargetId(targetId);
                dataScope.setScopeType(dataScopeType.getValue());
                dataScopes.add(dataScope);
            }
            this.dataScopeService.saveBatch(dataScopes);
        }
    }


    /**
     * 编辑角色
     *
     * @param dto 入参
     */
    @Transactional(rollbackFor = Exception.class)
    public void edit(RoleDTO dto, String organizationId,String systemCode) {
        //根据角色id获取角色
        Role role = this.checkSuper(dto.getId());
        //校验角色名称是否重复
        this.checkRoleName(dto, organizationId);
        BeanUtils.copyProperties(dto, role);
        this.roleMapper.updateById(role);
        //修改角色权限
        this.editRoleAuth(dto);
        //修改数据权限

        DataScopeTypeEnum dataScopeTypeEnum = DataScopeTypeEnum.ORGANIZATION;
        if(SystemCodeConstants.ORGANIZATION.equals(systemCode)){
            dataScopeTypeEnum = DataScopeTypeEnum.CAMPUS;
        }
        editDataScope(dto,dataScopeTypeEnum);
    }

    /**
     * 编辑角色权限
     *
     * @param dto 入参
     */
    private void editRoleAuth(RoleDTO dto) {
        this.roleMenuService.remove(new QueryWrapper<RoleMenu>().lambda().eq(RoleMenu::getRoleId, dto.getId()));
        this.addRoleAuth(dto.getMenuIds(), dto.getId());
    }

    /**
     * 编辑角色数据权限
     *
     * @param dto 入参
     */
    private void editDataScope(RoleDTO dto,DataScopeTypeEnum dataScopeType) {
        this.dataScopeService.remove(new QueryWrapper<SysDataScope>().lambda().eq(SysDataScope::getRoleId, dto.getId()));
        if(CollectionUtils.isNotEmpty(dto.getDataScopeIds())){
            this.addDataAuth(dto.getDataScopeIds(), dto.getId(),dataScopeType);
        }

    }

    /**
     * 删除
     *
     * @param roleId 角色id
     */
    @Transactional(rollbackFor = Exception.class)
    public void delete(String roleId) {
        this.checkSuper(roleId);
        //校验角色
        this.checkRole(roleId);
        this.roleMapper.deleteById(roleId);
        this.roleMenuService.remove(new QueryWrapper<RoleMenu>().lambda().eq(RoleMenu::getRoleId, roleId));
        this.dataScopeService.remove(new QueryWrapper<SysDataScope>().lambda().eq(SysDataScope::getRoleId, roleId));
    }

    /**
     * 校验超管角色
     *
     * @param roleId 角色id
     */
    private Role checkSuper(String roleId) {
        //根据角色id获取角色
        Role role = this.roleMapper.selectById(roleId);
        if (role.getIsSuper().equals(Boolean.TRUE)) {
            throw new BusinessException("禁止操作超级管理员数据");
        }
        return role;
    }

    /**
     * 校验角色
     *
     * @param roleId 角色id
     */
    private void checkRole(String roleId) {
        List<AccountRole> accountRoles = this.accountRoleService.list(new QueryWrapper<AccountRole>().lambda()
                .eq(AccountRole::getRoleId, roleId));
        if (ParamUtils.isNotEmpty(accountRoles)) {
            throw new BusinessException("该角色已被使用，无法删除");
        }
    }


    /**
     * 分页查询角色
     *
     * @param page     分页参数
     * @param roleName 角色名称
     * @return IPage<Role>
     */
    public IPage<RoleVO> page(Page<Role> page, String roleName, String organizationId) {
        //根据筛选条件查询每个单位非超管的角色
        IPage<Role> iPage = this.roleMapper.selectPage(page, new QueryWrapper<Role>().lambda()
                .like(ParamUtils.isNotEmpty(roleName), Role::getRoleName, roleName)
                .eq(Role::getIsSuper, false)
                .eq(Role::getOrganizationId, organizationId)
                .orderByDesc(BaseEntity::getCreatedDate));
        IPage<RoleVO> returnPage = iPage.convert(role -> BeanUtils.copyProperties(role, RoleVO.class));
        List<RoleVO> records = returnPage.getRecords();
        if (ParamUtils.isEmpty(records)) {
            return returnPage;
        }
        List<String> roleIds = records.stream().map(RoleVO::getId).collect(Collectors.toList());
        List<Menu> menus = this.roleMenuService.getRoleMenuByRoleId(roleIds);
        //数据权限
        List<SysDataScope> dataScopes = dataScopeService.getSysDataScopeByRoleId(roleIds);
        Map<String, Map<String, List<Menu>>> menuMap = menus.stream()
                .filter(f -> ParamUtils.isNotEmpty(f.getSystemCode()))
                .collect(Collectors.groupingBy(Menu::getSystemCode, Collectors.groupingBy(Menu::getRoleId)));

        Map<String, List<SysDataScope>> dataScopeMap = dataScopes.stream().collect(Collectors.groupingBy(SysDataScope::getRoleId));

        Map<String, List<Menu>> runMenuMap = menuMap.get(SystemCodeConstants.OPERATION);
        Map<String, List<Menu>> organizationMenuMap = menuMap.get(SystemCodeConstants.ORGANIZATION);

        List<RoleVO> results = records.stream().map(i -> {
            Map<String, List<AuthTreeVO>> maps = new HashMap<>();
            RoleVO roleVO = BeanUtils.copyProperties(i, RoleVO.class);
            if (runMenuMap != null && ParamUtils.isNotEmpty(runMenuMap.get(i.getId()))) {
                roleVO.setList(this.menuService.setTree(runMenuMap.get(i.getId())));
            }
            if (organizationMenuMap != null && ParamUtils.isNotEmpty(organizationMenuMap.get(i.getId()))) {
                maps.put(SystemCodeConstants.ORGANIZATION, this.menuService.setTree(organizationMenuMap.get(i.getId())));
            } else {
                maps.put(SystemCodeConstants.ORGANIZATION, new ArrayList<>());
            }

            if (CollectionUtils.isNotEmpty(dataScopeMap.get(i.getId()))) {
                roleVO.setDataScopeIds(dataScopeMap.get(i.getId()).stream().map(SysDataScope::getTargetId).collect(Collectors.toList()));
            } else {
                roleVO.setDataScopeIds(Lists.newArrayList());
            }
            roleVO.setMaps(maps);
            return roleVO;
        }).collect(Collectors.toList());

        returnPage.setRecords(results);
        return returnPage;
    }

    /**
     * 获取角色
     *
     * @param organizationId 角色所属单位
     * @return Map<String, Role>
     */
    public Map<String, Role> selectRoleMap(String organizationId) {
        return this.roleMapper.selectList(new QueryWrapper<Role>().lambda().eq(Role::getOrganizationId, organizationId)).stream()
                .collect(Collectors.toMap(BaseEntity::getId, Role -> Role));
    }

    /**
     * 获取角色权限
     *
     * @param id         角色id
     * @param systemCode 系统编码
     * @return List<AuthTreeVO>
     */
    public List<AuthTreeVO> auth(String id, String systemCode) {
        //获取角色菜单
        List<RoleMenu> roleMenus = this.roleMenuService.getRoleMenuByRoleId(id);
        if (ParamUtils.isEmpty(roleMenus)) {
            return new ArrayList<>();
        }
        List<String> menuIds = roleMenus.stream().map(RoleMenu::getMenuId).collect(Collectors.toList());
        //获取菜单
        LambdaQueryWrapper<Menu> menuQuery = new QueryWrapper<Menu>().lambda()
                .in(BaseEntity::getId, menuIds)
                .eq(Menu::getSystemCode, systemCode);
        List<Menu> menus = this.menuService.list(menuQuery);
        return this.menuService.setTree(menus);
    }


    /**
     * 获取所有非超管角色
     *
     * @param organizationId 机构id
     * @return List<Role>
     */
    public List<Role> allRole(String organizationId) {
        return this.roleMapper.selectList(new LambdaQueryWrapper<Role>()
                .eq(Role::getOrganizationId, organizationId)
                .eq(Role::getIsSuper, false)
                .orderByDesc(BaseEntity::getCreatedDate));
    }


    /**
     * 更改角色成员数量
     *
     * @param id     账号id  account表的id
     * @param status 变更的状态  account表的status
     */
    public void updateRoleMemberAmount(String id, Boolean status) {
        //获取账号角色
        LambdaQueryWrapper<AccountRole> eq = new LambdaQueryWrapper<AccountRole>()
                .eq(AccountRole::getAccountId, id);
        List<AccountRole> list = this.accountRoleService.list(eq);
        List<String> roleIds = list.stream().map(AccountRole::getRoleId).collect(Collectors.toList());
        Integer num = 1;
        if (status.equals(Boolean.FALSE)) {
            num = -1;
        }
        this.roleMapper.updateMemberAmount(roleIds, num);
    }

    public boolean isSuperAdminByAccountId(String accountId) {
        return roleMapper.getSuperCountByAccountId(accountId) > 0;
    }

    public DataScopeTableVO getDataScopeTable(String organizationId, List<String> useDataScopeIds) {
        if(CollectionUtils.isEmpty(useDataScopeIds)){
            useDataScopeIds = Lists.newArrayList();
        }
        DataScopeTableVO dataScopeTableVO = new DataScopeTableVO();
        List<SysDataScopeSelectVO> totalList = dataScopeService.getDataByRoleId(organizationId);
        List<SysDataScopeSelectVO> useList = Lists.newArrayList();
        List<SysDataScopeSelectVO> didList = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(totalList)) {
            List<String> finalUseDataScopeIds = useDataScopeIds;
            useList = totalList.stream().filter(item -> finalUseDataScopeIds.contains(item.getId())).collect(Collectors.toList());
            didList = totalList.stream().filter(item -> !finalUseDataScopeIds.contains(item.getId())).collect(Collectors.toList());
        }

        dataScopeTableVO.setDidList(didList);
        dataScopeTableVO.setUseList(useList);
        return dataScopeTableVO;
    }

    public boolean isSuper(String accountId) {
        return baseMapper.isSuper(accountId);
    }
}
